/*
 * SharpHSQL.cs
 *
 * Copyright (c) 2001, The HSQL Development Group
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 *
 * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * Neither the name of the HSQL Development Group nor the names of its
 * contributors may be used to endorse or promote products derived from this
 * software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * This package is based on HypersonicSQL, originally developed by Thomas Mueller.
 *
 * C# port by Mark Tutt
 * C# .NET Final Release port update by Pramod Kumar Singh
 *
 */
namespace SharpHSQL {
    using System;
    using System.IO;
    using System.Threading.Tasks;
    using System.Threading;
    //using System.Windows.Forms;

    public class SharpHSQL {
        public SharpHSQL() {
            //
            // TODO: Add Constructor Logic here
            //
        }
        static void Do() {
            // Create an in memory database
            Database db = new Database(".");
            Channel myChannel = db.Connect("sa", "");
            Result rs;
            string query = "";

            // do a little performance test
            Console.WriteLine("Running performance test.\n\n");
            query = "CREATE TABLE Addr(ID INT PRIMARY KEY, First CHAR, Name CHAR, ZIP INT)";
            db.Execute(query, myChannel);
            query = "CREATE INDEX iName ON Addr(Name)";
            db.Execute(query, myChannel);
            DateTime time = DateTime.Now;
            for (int i = 0; i < 10000; i++) {
                query = "INSERT INTO Addr VALUES(" + i + ",'Mark" + i + "'," + "'Tutt" + (10000 - i - (i % 31)) + "', " + (3000 + i % 100) + ")";
                rs = db.Execute(query, myChannel);
                if (rs.error != null) {
                    Console.WriteLine(rs.error);
                }
            }

            TimeSpan execution = DateTime.Now.Subtract(time);
            Console.WriteLine("Inserted 10000 records in " + ((Int64)execution.TotalMilliseconds).ToString() + " milliseconds, " + ((10000 * 1000) / ((Int64)execution.TotalMilliseconds)) + " inserts per second.");

            query = "SELECT * FROM Addr";
            rs = db.Execute(query, myChannel);
            if (rs.Size != 10000) {
                Console.WriteLine("An error occurred, rowcount should be 10000 but is " + rs.Size);
            }

            time = DateTime.Now;

            for (int i = 0; i < 10000; i++) {
                query = "UPDATE Addr SET Name='Michael" + (i + (i % 31)) + "' WHERE ID=" + i;
                rs = db.Execute(query, myChannel);
                if (rs.error != null) {
                    Console.WriteLine(rs.error);
                }
            }

            execution = DateTime.Now.Subtract(time);
            Console.WriteLine("Updated 10000 records in " + ((Int64)execution.TotalMilliseconds).ToString() + " milliseconds, " + ((10000 * 1000) / ((Int64)execution.TotalMilliseconds)) + " updates per second.");

            time = DateTime.Now;

            for (int i = 0; i < 10000; i++) {
                query = "SELECT * FROM Addr WHERE ID=" + (10000 - 1 - i);
                rs = db.Execute(query, myChannel);
                if (rs.error != null) {
                    Console.WriteLine(rs.error);
                }
            }

            execution = DateTime.Now.Subtract(time);
            Console.WriteLine("Executed 10000 selects in " + ((Int64)execution.TotalMilliseconds).ToString() + " milliseconds, " + ((10000 * 1000) / ((Int64)execution.TotalMilliseconds)) + " selects per second.");

            time = DateTime.Now;

            for (int i = 0; i < 10000; i++) {
                query = "DELETE FROM Addr WHERE ID=" + (10000 - 1 - i);
                rs = db.Execute(query, myChannel);
                if (rs.error != null) {
                    Console.WriteLine(rs.error);
                }
            }

            execution = DateTime.Now.Subtract(time);
            Console.WriteLine("Deleted 10000 records in " + ((Int64)execution.TotalMilliseconds).ToString() + " milliseconds, " + ((10000 * 1000) / ((Int64)execution.TotalMilliseconds)) + " deletes per second.");

            Console.WriteLine("\nInteractive SQL ready, type 'quit' to exit\n");

            query = "";

            while (!query.ToLower().Equals("quit")) {
                Console.Write("SQL> ");
                query = Console.ReadLine();
                if (!query.ToLower().Equals("quit")) {
                    rs = db.Execute(query, myChannel);
                    if (rs.error != null) {
                        Console.WriteLine(rs.error);
                    } else {
                        Console.Write(rs.Size+ " rows returned, " + rs.updateCount + " rows affected.\n\n");
                        if (rs.Root != null) {
                            Record r = rs.Root;
                            int column_count = rs.ColumnCount;
                            for (int x = 0; x < column_count; x++) {
                                Console.Write(rs.label[x]);
                                Console.Write("\t");
                            }
                            Console.Write("\n");
                            while (r != null) {
                                for (int x = 0; x < column_count; x++) {
                                    Console.Write(r.data[x]);
                                    Console.Write("\t");
                                }
                                Console.Write("\n");
                                r = r.next;
                            }
                            Console.Write("\n");
                        }
                    }
                }
            }
            
        }

        [STAThread]
        public static void Main(string[] args) {
            Test();
            //Application.Run(new Form());
        }

        public static void Test() {
            Database db = new Database(".");
            Channel myChannel = db.Connect("sa", "");
            Result rs;

            Console.WriteLine("Running performance test.\n\n");
            var query = "CREATE TABLE Addr(ID INT PRIMARY KEY, First CHAR, Name CHAR, ZIP INT)";
            db.Execute(query, myChannel);
            query = "CREATE INDEX iName ON Addr(Name)";
            db.Execute(query, myChannel);

            var taskFactory = new TaskFactory();
            var selectTask = new Task(() => {
                for (int j = 0; j < 10; j++) {
                    var t = DateTime.Now;

                    for (int i = 0; i < 10000; i++) {
                        var q = "SELECT * FROM Addr WHERE ID=" + (10000 - 1 - i);
                        var r = db.Execute(q, myChannel);
                        if (r.error != null) {
                            Console.WriteLine(r.error);
                        }
                    }

                    var execution = DateTime.Now.Subtract(t);
                    Console.WriteLine( j + ": Executed 10000 selects in " + ((Int64)execution.TotalMilliseconds).ToString() + " milliseconds, " + ((10000 * 1000) / ((Int64)execution.TotalMilliseconds)) + " selects per second.");
                    Thread.Sleep(10);
                }
            });

            var insertTask = new Task(() => {
                for (int j = 0; j < 10; j++) {
                    var t = new System.Diagnostics.Stopwatch();
                    t.Start();
                    for (int i = 10000 * j; i < 10000 * (j+1); i++) {
                        query = "INSERT INTO Addr VALUES(" + i + ",'Mark" + i + "'," + "'Tutt" + (10000 - i - (i % 31)) + "', " + (3000 + i % 100) + ")";
                        rs = db.Execute(query, myChannel);
                        if (rs.error != null) {
                            Console.WriteLine(rs.error);
                        }
                    }
                    t.Stop();
                    Console.WriteLine(j + ": Inserted 10000 records in " + ((Int64)t.ElapsedMilliseconds).ToString() + " milliseconds, " + ((10000 * 1000) / ((Int64)t.ElapsedMilliseconds)) + " inserts per second.");

                }
                Thread.Sleep(10);
            });

            selectTask.Start();
            insertTask.Start();

            Console.Read();
        }
    }
}